//
//  NSAttributedStringAdditions.m
//  MailDelivery
//
//  Created by Dante Palacios on 03/09/09.
//  Copyright 2009 Dante Palacios. All rights reserved.
//

#import "NSAttributedStringAdditions.h"

#import "NSStringAdditions.h"
#import "NSTextAttachmentAdditions.h"

#import "Macros.h"


@interface _MDAttributedStringHelper : NSObject
{
	NSAttributedString *_attributedString;
	
	NSString *_plainText;
	NSString *_HTMLString;
	NSArray *_attachments;
}

@property (retain) NSAttributedString *attributedString;
@property (readonly) NSString *plainText;
@property (readonly) NSString *HTMLString;
@property (readonly) NSArray *attachments;

@end

@implementation _MDAttributedStringHelper

- (void)dealloc {
	[_attributedString release], _attributedString = nil;
	[_plainText release], _plainText = nil;
	[_HTMLString release], _HTMLString = nil;

	[super dealloc];
}

- (NSAttributedString *)attributedString {
	return AtomicAutoreleasedGet(_attributedString);
}

- (void)setAttributedString:(NSAttributedString *)value {
	 AtomicRetainedSet(_attributedString, value);
}

- (NSString *)plainText 
{
	NSString *value = nil;
	@synchronized(self) 
    {
		if (!_plainText) 
        {
			NSAttributedString *attributedString = self.attributedString;
			NSData *rtfData = [attributedString RTFFromRange:NSMakeRange(0, attributedString.length) documentAttributes:nil];
			NSAttributedString *rtf = [[NSAttributedString alloc] initWithRTF:rtfData documentAttributes:NULL];
			if (rtf) {
				NSString *defaultValue = [rtf string];
				NSStringEncoding encoding = defaultValue.encoding;
				NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
											NSPlainTextDocumentType, NSDocumentTypeDocumentAttribute,
											[NSNumber numberWithUnsignedInteger:encoding], NSCharacterEncodingDocumentOption,
											nil];
				
				NSError *error = nil;
				NSData *data = [rtf dataFromRange:NSMakeRange(0, rtf.length) documentAttributes:attributes error:&error];
				[rtf release];
				
				@try {
					if (error) 
                    {
						NSLog(@"Warning!, Unable to covert to Plain Text…\r\nError:%@", [error localizedDescription]);
						_plainText = [defaultValue retain];
					}
                    else 
                    {
						_plainText = [[NSString alloc] initWithData:data encoding:encoding];	
					}
				}
				@catch (NSException * e) {
					NSLog(@"Warning!, Exception raised…\r\n%@:%@", [e name], [e reason]);
					_plainText = [[attributedString string] retain];
				}
				
			}else {
				NSLog(@"Warning!, Unable to covert to Plain Text…");
				_plainText = [[attributedString string] retain];
			}
		}
		value = [[_plainText copy] autorelease];
	}
	
	return value;
}

- (NSString *)HTMLString
{
	NSString *value = nil;
	@synchronized(self)
	{
		if (!_HTMLString)
		{
			NSAttributedString *attributedString = self.attributedString;
			NSString *defaultValue = [attributedString string];
			NSStringEncoding encoding = defaultValue.encoding;
			NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
										NSHTMLTextDocumentType, NSDocumentTypeDocumentAttribute,
										[NSNumber numberWithUnsignedInteger:encoding], NSCharacterEncodingDocumentOption, [NSArray arrayWithObjects:@"DOCTYPE", @"XML", nil], NSExcludedElementsDocumentAttribute, nil];
			
			NSError *error = nil;
			NSData *data = [attributedString dataFromRange:NSMakeRange(0, attributedString.length) documentAttributes:attributes error:&error];
			if (error) {
				NSLog(@"Unable to covert to HTML, Error:%@", [error localizedDescription]);
				_HTMLString = [defaultValue copy];
			}	
			else {
				_HTMLString = [[NSString alloc] initWithData:data encoding:encoding];
			}
				
		}
		value = [[_HTMLString copy] autorelease];
	}
	
	return value;
}

- (NSArray *)attachments 
{
	NSArray *value = nil;
	@synchronized(self)
	{
		if (!_attachments)
		{
			NSAttributedString *attributedString = self.attributedString;
			if (!attributedString || !attributedString.length || ![attributedString containsAttachments]) return nil;
			
			NSMutableArray *attachments = [NSMutableArray array];
			NSRange range = NSMakeRange(0, attributedString.length);
			NSUInteger index = 0;
			while (index < range.length) 
			{
				NSRange effectiveRange;
				NSDictionary *attributes = [attributedString attributesAtIndex:index longestEffectiveRange:&effectiveRange inRange:range];
				NSTextAttachment *attachment = [attributes objectForKey:NSAttachmentAttributeName];
				NSFileWrapper *fileWrapper = [attachment fileWrapper];
				if (attachment)
				{
					if (!fileWrapper)
					{
						NSError *error = nil;
						NSDictionary *documentAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
															NSRTFDTextDocumentType, NSDocumentTypeDocumentAttribute,
															nil];
						
						NSFileWrapper *selializedFileWrapper = [attributedString fileWrapperFromRange:effectiveRange documentAttributes:documentAttributes error:&error];
						
						NSData *serializedDataRepresentation = [selializedFileWrapper serializedRepresentation];
						if (serializedDataRepresentation)
						{
							fileWrapper = [[NSFileWrapper alloc] initWithSerializedRepresentation:serializedDataRepresentation];
							
							NSString *filename = [fileWrapper filename];
							if (!filename && !(filename = [fileWrapper preferredFilename]))
							{
								if ((filename = [attachment filename])) 
								{
									[fileWrapper setPreferredFilename:filename];
									[fileWrapper setFilename:filename];
									
									[attachment setFileWrapper:fileWrapper];
									[attachments addObject:attachment];
								}
							}
							
							[fileWrapper release];
						}
					}
					else
					{
						[attachments addObject:attachment];
					}
				}
				
				index = effectiveRange.location + effectiveRange.length;
			}		
			_attachments = [attachments retain];
		}
		value = [[_attachments retain] autorelease];
	}
	
	return value;
}

@end

@implementation NSAttributedString(MailDeliveryStandardAdditions)

- (NSString *)HTMLString
{
	_MDAttributedStringHelper *helper = [[_MDAttributedStringHelper alloc] init];
	helper.attributedString = self;
	
	if (![[NSThread currentThread] isEqual:[NSThread mainThread]])
	{
		[helper performSelectorOnMainThread:@selector(HTMLString) withObject:nil waitUntilDone:YES];
	}
	
	NSString *string = [helper HTMLString];
	
	[helper release];
	
	return string;
}

- (NSString *)plainText
{
	_MDAttributedStringHelper *helper = [[_MDAttributedStringHelper alloc] init];
	helper.attributedString = self;
	if (![[NSThread currentThread] isEqual:[NSThread mainThread]])
	{
		[helper performSelectorOnMainThread:@selector(plainText) withObject:nil waitUntilDone:YES];
	}
	
	NSString *string = [helper plainText];
	
	[helper release];
	
	return string;
}

- (NSArray *)attachments
{
	_MDAttributedStringHelper *helper = [[_MDAttributedStringHelper alloc] init];
	helper.attributedString = self;
	if (![[NSThread currentThread] isEqual:[NSThread mainThread]])
	{
		[helper performSelectorOnMainThread:@selector(attachments) withObject:nil waitUntilDone:YES];
	}
	
	NSArray *attachments = [helper attachments];
	
	[helper release];
	
	return attachments;
}

@end
